// Copyright 2017 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/////////////////////////////////////////////////////////
// includes
/////////////////////////////////////////////////////////
#include "mlAxpy.h"
#include "bar.h"
#include "utils.h"
#include "bench.h"

/////////////////////////////////////////////////////////
// shared globals
/////////////////////////////////////////////////////////

  __attribute__ ((section(".heapsram"))) static const float fv0[400] = { 15.0337238F, 47.6492348F, 32.1463203F,
    36.719532F, 27.9067287F, 15.1456299F, 15.6785078F, 16.4370308F, 1.62118244F,
    51.1055603F, 7.57770967F, 30.5438633F, 74.7655182F, 66.3858948F, 43.1216087F,
    0.182829559F, 15.1056366F, 91.365593F, 30.7762737F, 45.3304F, 84.2023163F,
    14.6472158F, 81.8232422F, 87.0193863F, 51.2713852F, 54.0399F, 5.89708185F,
    40.882164F, 74.4691162F, 66.1355133F, 86.442131F, 6.99611807F, 82.8370895F,
    74.1432F, 43.8764572F, 33.7652855F, 87.0179138F, 36.4060059F, 41.0990791F,
    46.7791862F, 81.6365204F, 65.0692368F, 95.0078506F, 65.8608093F, 52.7551193F,
    72.5657349F, 55.6344833F, 52.8448715F, 48.0980759F, 51.4331779F, 75.3225861F,
    89.844017F, 19.1099281F, 57.703846F, 54.0918503F, 64.8631287F, 8.75913906F,
    80.7338181F, 52.1174965F, 78.5742874F, 26.7444973F, 77.3107F, 68.9984055F,
    3.91880488F, 47.2511597F, 25.9368057F, 32.7052F, 58.1403084F, 73.9813919F,
    91.8186951F, 64.5060272F, 73.6262817F, 43.6885376F, 2.15982056F, 65.5854187F,
    59.0946655F, 25.6324749F, 58.8630219F, 28.8666382F, 82.1373749F, 75.6578064F,
    75.2520599F, 67.0747757F, 3.13552666F, 87.8290482F, 21.3591957F, 37.1818771F,
    81.6265717F, 38.6720085F, 5.19741964F, 10.8005295F, 4.60907269F, 13.2607117F,
    28.8623199F, 1.90354335F, 21.2803211F, 21.3118782F, 98.896286F, 28.0981941F,
    3.71524096F, 53.8106346F, 66.3496094F, 44.9309044F, 56.8349571F, 74.3985062F,
    41.4033165F, 49.0077209F, 33.1853027F, 79.9907303F, 64.609108F, 74.6959763F,
    67.3073959F, 50.5020103F, 2.13671374F, 53.2153168F, 86.5194931F, 26.7075672F,
    87.6855698F, 25.8804092F, 27.100523F, 41.3029938F, 71.4251556F, 9.58354092F,
    12.2217665F, 49.3763275F, 86.3360138F, 89.2437286F, 6.56881809F, 20.8557587F,
    80.7405853F, 67.8948593F, 32.5302277F, 98.8895416F, 17.5671673F,
    0.946677148F, 75.6345749F, 91.4368362F, 57.0642967F, 33.8062286F, 89.496933F,
    94.6526337F, 99.2270432F, 48.6580658F, 25.5661297F, 36.9683647F, 79.8953705F,
    94.6857376F, 87.2550507F, 14.8939734F, 44.4396858F, 40.6023788F, 96.9144F,
    15.8402901F, 11.0954647F, 68.0687637F, 60.3708496F, 64.1570129F, 28.5142288F,
    24.3771935F, 52.3078651F, 30.5549889F, 26.4708271F, 1.69496095F, 27.0630894F,
    97.993042F, 98.6250763F, 1.41319358F, 67.5790405F, 36.1878853F, 0.322476655F,
    39.3738289F, 49.1926613F, 87.071167F, 74.5754547F, 68.6314392F, 38.690239F,
    62.0016975F, 53.6217918F, 39.4184456F, 16.1171341F, 5.29939556F, 12.8136969F,
    99.44841F, 87.7742462F, 90.4008102F, 26.8820515F, 51.0897369F, 51.8831329F,
    87.8809509F, 18.1966114F, 86.6907425F, 79.7487F, 90.7982712F, 77.1698074F,
    91.6136551F, 79.2231F, 14.7371521F, 22.3919792F, 79.9798F, 77.4158783F,
    92.3568192F, 22.2665195F, 66.8992767F, 3.23332596F, 41.2595863F, 35.0673523F,
    9.96339512F, 59.6277695F, 37.1644325F, 40.6956253F, 42.3831749F, 94.3820114F,
    81.896965F, 32.6832619F, 9.91227436F, 16.8782F, 61.7439346F, 83.4131546F,
    78.0775452F, 37.4708214F, 16.5123501F, 87.9859543F, 7.43516588F, 3.07324052F,
    53.9771652F, 70.3174591F, 55.4067841F, 18.7667694F, 74.4634323F, 19.2925434F,
    39.6188889F, 90.7393875F, 80.8721924F, 47.6122437F, 15.5631313F, 35.970253F,
    82.7281494F, 94.1961746F, 68.7576599F, 98.0293503F, 76.7451553F, 68.4051895F,
    33.8732452F, 32.134903F, 47.3710938F, 52.8356743F, 77.1630325F, 8.02466202F,
    23.0132351F, 65.8486F, 6.06878138F, 70.6569595F, 82.2506638F, 96.893074F,
    49.2096405F, 90.7360687F, 22.2969513F, 8.16068745F, 66.8912048F, 17.6866646F,
    88.7919693F, 21.2462063F, 75.1277313F, 39.0340691F, 87.2589F, 89.6931152F,
    94.5871735F, 74.978981F, 95.0435181F, 54.9012566F, 11.4927053F, 11.0236292F,
    37.5475044F, 29.6749611F, 6.02034473F, 31.7340889F, 81.1470261F, 0.532971F,
    22.3371601F, 53.2266693F, 95.6693954F, 23.9452019F, 81.9586487F, 99.8064346F,
    59.6750793F, 77.9726486F, 57.9006767F, 11.5466957F, 62.943428F, 33.8798599F,
    28.667572F, 52.2365036F, 42.2732086F, 37.307682F, 6.55620337F, 5.40286207F,
    23.0679245F, 21.6365376F, 11.849659F, 65.7456436F, 81.925766F, 10.4592848F,
    90.6028F, 11.2817059F, 1.08777857F, 73.6531448F, 4.17549181F, 12.2378922F,
    14.4597034F, 80.3186417F, 1.98167598F, 31.1218948F, 21.8694267F, 94.6650848F,
    42.6654434F, 39.9773865F, 25.0981731F, 96.3102F, 87.3237F, 13.7914648F,
    80.3096237F, 99.6120682F, 8.13177F, 59.5181236F, 16.5624218F, 93.7439041F,
    17.8204479F, 22.0125141F, 81.9786606F, 69.1680222F, 25.4892521F, 4.90299702F,
    58.2213287F, 63.0562439F, 75.0185471F, 6.63523531F, 57.7213058F, 89.7700806F,
    81.3141632F, 99.7174F, 19.9691753F, 71.4701233F, 78.2137604F, 44.3097496F,
    66.2436752F, 48.0206F, 35.0119438F, 6.99646711F, 18.7865429F, 56.857872F,
    3.37520885F, 89.278923F, 49.8361053F, 50.2846413F, 34.9995117F, 50.6868973F,
    47.3631248F, 19.8063469F, 94.6781235F, 19.4365158F, 66.4246063F, 94.5638962F,
    34.4265137F, 38.994133F, 1.41760337F, 97.7640686F, 83.6702118F, 10.5756807F,
    95.3704758F, 0.348908365F, 63.3066521F, 67.5458908F, 9.39907074F,
    42.2243309F, 34.4417648F, 81.4215317F, 10.1183786F, 55.2093773F, 42.4176483F,
    82.1603088F, 80.0776138F, 86.7889862F, 24.3788719F, 74.5068893F, 8.86308289F,
    78.3887939F, 23.9180908F, 76.5154114F, 63.5355034F, 60.1694794F, 29.2272701F,
    85.2518921F, 5.29464865F, 63.530159F, 63.9597397F, 38.2193871F, 22.4613323F,
    3.75050068F, 18.1357632F, 74.9887085F };

  __attribute__ ((section(".heapsram"))) static const float fv1[400] = { 87.825325F, 3.47576427F, 87.928772F,
    95.0295563F, 16.5634785F, 22.8386974F, 33.6366196F, 88.5114F, 28.4118385F,
    36.8428192F, 9.87349606F, 54.9044952F, 41.0594673F, 58.4516411F, 21.3720226F,
    53.6629105F, 46.688076F, 96.041275F, 62.3385925F, 18.4934025F, 40.622921F,
    99.4190445F, 97.0196381F, 21.5635548F, 62.4900589F, 66.0594482F, 63.7608185F,
    89.9893799F, 22.9542046F, 88.2405319F, 39.58498F, 58.8711319F, 24.5182896F,
    37.6823F, 23.1945457F, 39.2425613F, 96.5938F, 74.9767685F, 72.956604F,
    22.163147F, 73.3745422F, 56.1790962F, 64.7114258F, 63.7664909F, 93.7314224F,
    49.1730728F, 55.3195305F, 13.4098148F, 53.9723F, 29.0959206F, 77.9995346F,
    39.5978088F, 9.58128F, 23.589056F, 33.3461189F, 60.5131721F, 99.0484924F,
    69.3621826F, 50.6406059F, 10.9103317F, 97.2274475F, 25.1775589F, 74.4303818F,
    68.6796646F, 96.5567856F, 94.4155884F, 82.4331284F, 13.7050209F, 99.6751328F,
    45.4158745F, 30.4072742F, 88.2303F, 77.6259079F, 90.7282639F, 40.2871399F,
    96.6584473F, 99.3203506F, 88.5299301F, 88.483757F, 16.2790947F, 99.5002213F,
    84.8730164F, 77.1589661F, 3.18955779F, 29.8608837F, 30.8454609F, 21.302124F,
    51.5677528F, 74.9636765F, 27.2361908F, 67.1887436F, 0.375581682F,
    42.4164886F, 77.5761108F, 95.1774F, 50.7547569F, 99.671814F, 21.1048851F,
    32.7514267F, 76.6614532F, 8.95646763F, 52.0371399F, 92.3149719F, 83.3476334F,
    84.3693542F, 98.2441635F, 18.2575226F, 22.4473476F, 33.8654518F, 69.2995834F,
    44.5192451F, 52.9905F, 11.4066248F, 15.9707355F, 76.6303635F, 30.0862465F,
    47.0716591F, 58.1601715F, 31.9911499F, 73.7120361F, 23.5624352F, 27.538559F,
    31.0425549F, 91.0482635F, 58.8268852F, 12.1800098F, 61.5287361F, 17.9430599F,
    12.7522068F, 12.9925976F, 91.4912338F, 37.7040253F, 60.8733749F, 14.8763294F,
    79.1186905F, 30.8576622F, 1.31583643F, 21.3467522F, 73.8685684F, 84.7277069F,
    12.7970486F, 40.5737762F, 19.2064362F, 73.9326782F, 80.8335114F, 94.4546F,
    79.824791F, 81.2521057F, 18.0356026F, 16.013628F, 11.1519451F, 73.4929657F,
    20.4120903F, 34.2669182F, 12.580081F, 66.9520493F, 84.5809479F, 93.5709457F,
    31.8901844F, 74.4249F, 79.4434F, 8.22010136F, 15.6643391F, 88.9524307F,
    90.0714264F, 98.0023117F, 32.8003616F, 69.1515503F, 4.3189764F, 77.0260162F,
    64.5218201F, 5.0747962F, 32.6566277F, 55.7268867F, 96.2995758F, 64.2486877F,
    20.1759796F, 14.32969F, 12.7674685F, 1.86489606F, 59.2104149F, 82.1644745F,
    57.413063F, 46.6207504F, 36.7692719F, 24.3484917F, 28.566864F, 28.505743F,
    5.0962038F, 74.9750748F, 79.3678131F, 70.382225F, 74.2682419F, 68.2450714F,
    36.3070259F, 91.3465195F, 17.0747414F, 40.226181F, 87.845253F, 34.6302376F,
    16.567749F, 84.5536118F, 24.3023205F, 38.2000046F, 98.7658234F, 86.2312088F,
    26.3582153F, 76.8422699F, 46.4834862F, 47.7637482F, 55.7896194F, 54.5952F,
    16.511158F, 84.8538284F, 92.5121155F, 77.2262955F, 1.46880615F, 78.4298935F,
    33.1239624F, 37.3424F, 5.35582447F, 43.2004166F, 45.7875023F, 24.4751263F,
    90.6218719F, 38.5656624F, 11.1893702F, 79.1594849F, 14.6631136F, 42.5172501F,
    59.2903252F, 0.497886509F, 56.343502F, 30.0483952F, 35.4329376F, 41.021019F,
    61.4652863F, 39.1375656F, 18.0526104F, 87.6770706F, 17.6014538F, 19.9684238F,
    46.8751068F, 3.45960855F, 69.606308F, 19.5649281F, 24.3973866F, 70.2715912F,
    39.7033882F, 27.6035423F, 81.104454F, 61.0279121F, 60.1438637F, 38.1090698F,
    15.3843241F, 16.0713196F, 25.1823502F, 54.540741F, 63.0057487F, 9.94394779F,
    52.0657463F, 56.2042274F, 91.8685379F, 17.7284641F, 35.9604759F, 56.9257507F,
    33.7976341F, 62.8519592F, 54.8415756F, 43.412693F, 98.781517F, 34.601F,
    55.8982048F, 97.0059509F, 12.4400234F, 72.0404F, 45.9941254F, 32.7924194F,
    67.517395F, 51.9012146F, 16.5235138F, 89.4719849F, 74.4719467F, 19.4351883F,
    86.3639F, 56.5730553F, 45.5659752F, 31.1726265F, 70.8896942F, 37.6876373F,
    56.1654091F, 10.9529858F, 88.7639389F, 82.8144836F, 99.0788345F, 41.6797409F,
    15.4245424F, 81.7542496F, 15.4643497F, 11.1925077F, 33.6409569F, 65.802F,
    1.3730092F, 45.1816025F, 20.9697018F, 6.10119677F, 73.342659F, 25.8362484F,
    26.7904797F, 40.1877251F, 26.8467751F, 48.0785F, 79.2010498F, 0.453753144F,
    42.1281281F, 76.7869949F, 56.4001808F, 55.9775467F, 9.97231483F, 85.2548218F,
    74.9961395F, 19.2333889F, 54.1588821F, 34.4350395F, 1.88401878F, 70.7673721F,
    97.8156052F, 43.1243935F, 45.230381F, 55.5021362F, 64.7588654F, 27.6687908F,
    75.5020294F, 56.0641785F, 66.4983673F, 25.1812763F, 56.0612717F, 20.4273567F,
    14.8769817F, 5.17969F, 33.1938934F, 0.997090161F, 45.4932594F, 31.3083839F,
    91.8452F, 36.4349747F, 66.7153702F, 23.1038666F, 13.8272152F, 55.1626511F,
    34.6112785F, 67.1100159F, 59.2982941F, 68.4904251F, 43.137722F, 13.2671499F,
    17.3535938F, 66.997612F, 41.1896248F, 96.735878F, 67.1528778F, 2.96778679F,
    8.91999912F, 27.9814816F, 96.6628571F, 64.1652527F, 39.1092224F, 88.0085F,
    16.4642601F, 50.4965286F, 9.37268925F, 63.7856522F, 3.36577201F, 53.5212631F,
    32.2904968F, 56.7991257F, 86.607F, 83.3417511F, 51.8215332F, 41.7747345F,
    49.7802162F, 48.5091591F, 19.2404728F, 42.6991882F, 90.6176F, 52.1811256F,
    21.7395115F, 94.4438171F, 52.0721359F, 58.9036331F, 58.3256493F, 27.4140968F,
    38.5893974F, 55.2834053F, 10.1396942F, 85.4398499F, 28.5925388F, 20.5920181F,
    46.6780586F, 86.7842865F };

  __attribute__ ((section(".heapsram"))) static const float fv2[4] = { 29.0024052F, 16.8149376F, 42.0270653F,
    86.9266739F };

  __attribute__ ((section(".heapsram"))) static const float fv3[16] = { 167475.188F, 167471.844F, 738649.812F,
    738635.062F, 86825.1797F, 86823.4453F, 257317.766F, 257312.609F, 205468.344F,
    205464.25F, 1.28340175E+6F, 1.283376E+6F, 401982.344F, 401974.281F,
    5.192556E+6F, 5.192452E+6F };


/////////////////////////////////////////////////////////
// subfunctions
/////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////
// main testing function 
/////////////////////////////////////////////////////////
int main(int argc, const char * const argv[])
{
  (void)argc;
  (void)argv;

  int coreid;

  boolean_T pass;
  boolean_T flag;
  int k;
  float y[100];
  int ix;

  float b_y;
  float xbar;
  int b_k;
  float r;
  float c_y;
  float check[2];
  float golden[4];

  /////////////////////////////////////////////////////////
  // main test loop 
  // each core loops over a kernel instance
  /////////////////////////////////////////////////////////
  
  coreid = get_core_id();

  printf("starting %d kernel iterations... (coreid = %d)\n",KERNEL_ITS,coreid);

  if (coreid>3)
    coreid=coreid-4;

  synch_barrier();

  perf_begin();

  for(k = 0; k < getKernelIts(); k++)
  {
    // matlab kernel
    for (ix = 0; ix < 100; ix++) {
      y[ix] = fv2[coreid] * fv1[ix + 100 * coreid] + fv0[ix + 100 * coreid];

    }
  }

  synch_barrier();

  perf_end();

  /////////////////////////////////////////////////////////
  // check results
  /////////////////////////////////////////////////////////

  b_y = y[0];
  ix = 0;
  xbar = y[0];
  for (b_k = 0; b_k < 99; b_k++) {
    b_y += y[b_k + 1];
    ix++;
    xbar += y[ix];
  }

  xbar *= 1.0F/100.0F;
  ix = 0;
  r = y[0] - xbar;
  c_y = r * r;
  for (b_k = 0; b_k < 99; b_k++) {
    ix++;
    r = y[ix] - xbar;
    c_y += r * r;
  }
  synch_barrier();
  
  c_y *= 1.0F/99.0F;
  check[0] = b_y;
  check[1] = c_y;
  pass = true;
  flag = true;

  for (ix = 0; ix < 2; ix++) {
    for (b_k = 0; b_k < 2; b_k++) {
      golden[b_k + (ix << 1)] = fv3[(b_k + (ix << 1)) + (coreid << 2)];
    }
    flag = true;
    flag = (check[ix] <= golden[ix << 1]);
    flag = flag && (check[ix] >= golden[1 + (ix << 1)]);
    printErrors(!flag, ix, check[ix], golden[1 + (ix << 1)], golden[ix << 1]);
    pass = pass && flag;
  }
  
  flagPassFail(pass, get_core_id());
  
/////////////////////////////////////////////////////////
// exit
/////////////////////////////////////////////////////////


  return !pass;

}

